<template>
  <div class="app-container cam-page">
    <div class="cam-content">
      <section class="panel cam-banner">
        <div class="banner-text">
          <h2>电动车充电记录</h2>
          <p>实时追踪充电过程与费用，保障能源使用透明高效。</p>
        </div>
        <div class="banner-side">
          <div class="banner-stat">
            <span class="stat-label">当前记录</span>
            <span class="stat-value">{{ total }}</span>
          </div>
          <el-button
            class="chart-cta-btn"
            type="primary"
            icon="el-icon-s-data"
            @click="openChartDialog"
          >智能统计图</el-button>
          <span class="cta-tip">一键生成用电量/费用趋势并可下载</span>
        </div>
      </section>

      <section class="panel search-panel" v-show="showSearch">
        <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="auto" class="cam-form">
      <el-form-item label="电动车ID" prop="vehicleId">
        <el-input
          v-model="queryParams.vehicleId"
          placeholder="请输入电动车ID"
          clearable
          @keyup.enter.native="handleQuery"
        />
      </el-form-item>
      <el-form-item label="充电桩编号" prop="stationId">
        <el-input
          v-model="queryParams.stationId"
          placeholder="请输入充电桩编号"
          clearable
          @keyup.enter.native="handleQuery"
        />
      </el-form-item>
      <el-form-item label="开始充电时间" prop="startTime">
        <el-date-picker clearable
          v-model="queryParams.startTime"
          type="date"
          value-format="yyyy-MM-dd"
          placeholder="请选择开始充电时间">
        </el-date-picker>
      </el-form-item>
      <el-form-item label="结束充电时间" prop="endTime">
        <el-date-picker clearable
          v-model="queryParams.endTime"
          type="date"
          value-format="yyyy-MM-dd"
          placeholder="请选择结束充电时间">
        </el-date-picker>
      </el-form-item>
      <el-form-item label="用电量(kWh)" prop="powerUsed">
        <el-input
          v-model="queryParams.powerUsed"
          placeholder="请输入用电量(kWh)"
          clearable
          @keyup.enter.native="handleQuery"
        />
      </el-form-item>
      <el-form-item label="是否异常充电" prop="abnormalFlag">
        <el-input
          v-model="queryParams.abnormalFlag"
          placeholder="请输入是否异常充电"
          clearable
          @keyup.enter.native="handleQuery"
        />
      </el-form-item>
      <el-form-item label="充电费用" prop="feeAmount">
        <el-input
          v-model="queryParams.feeAmount"
          placeholder="请输入充电费用"
          clearable
          @keyup.enter.native="handleQuery"
        />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
      </el-form-item>
        </el-form>
      </section>

      <section class="panel toolbar-panel">
        <el-row :gutter="10" class="mb8 cam-toolbar">
      <el-col :span="1.5">
        <el-button
          type="primary"
          plain
          icon="el-icon-plus"
          size="mini"
          @click="handleAdd"
          v-hasPermi="['system:chargingofCam:add']"
        >新增</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="success"
          plain
          icon="el-icon-edit"
          size="mini"
          :disabled="single"
          @click="handleUpdate"
          v-hasPermi="['system:chargingofCam:edit']"
        >修改</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="danger"
          plain
          icon="el-icon-delete"
          size="mini"
          :disabled="multiple"
          @click="handleDelete"
          v-hasPermi="['system:chargingofCam:remove']"
        >删除</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="warning"
          plain
          icon="el-icon-download"
          size="mini"
          @click="handleExport"
          v-hasPermi="['system:chargingofCam:export']"
        >导出</el-button>
      </el-col>
      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
        </el-row>
      </section>

      <section class="panel table-panel">
        <div class="table-shell">
    <el-table v-loading="loading" :data="chargingofCamList" @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55" align="center" />
      <el-table-column label="充电记录ID" align="center" prop="chargeId" />
      <el-table-column label="电动车ID" align="center" prop="vehicleId" />
      <el-table-column label="充电桩编号" align="center" prop="stationId" />
      <el-table-column label="开始充电时间" align="center" prop="startTime" width="180">
        <template slot-scope="scope">
          <span>{{ parseTime(scope.row.startTime, '{y}-{m}-{d}') }}</span>
        </template>
      </el-table-column>
      <el-table-column label="结束充电时间" align="center" prop="endTime" width="180">
        <template slot-scope="scope">
          <span>{{ parseTime(scope.row.endTime, '{y}-{m}-{d}') }}</span>
        </template>
      </el-table-column>
      <el-table-column label="用电量(kWh)" align="center" prop="powerUsed" />
      <el-table-column label="是否异常充电" align="center" prop="abnormalFlag" />
      <el-table-column label="充电费用" align="center" prop="feeAmount" />
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
        <template slot-scope="scope">
          <el-button
            size="mini"
            type="text"
            icon="el-icon-edit"
            @click="handleUpdate(scope.row)"
            v-hasPermi="['system:chargingofCam:edit']"
          >修改</el-button>
          <el-button
            size="mini"
            type="text"
            icon="el-icon-delete"
            @click="handleDelete(scope.row)"
            v-hasPermi="['system:chargingofCam:remove']"
          >删除</el-button>
        </template>
      </el-table-column>
    </el-table>
        </div>
        <div class="pagination-wrap">
          <pagination
            v-show="total>0"
            :total="total"
            :page.sync="queryParams.pageNum"
            :limit.sync="queryParams.pageSize"
            @pagination="getList"
          />
        </div>
      </section>
    </div>

    <!-- 添加或修改电动车充电记录对话框 -->
    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="电动车ID" prop="vehicleId">
          <el-input v-model="form.vehicleId" placeholder="请输入电动车ID" />
        </el-form-item>
        <el-form-item label="充电桩编号" prop="stationId">
          <el-input v-model="form.stationId" placeholder="请输入充电桩编号" />
        </el-form-item>
        <el-form-item label="开始充电时间" prop="startTime">
          <el-date-picker clearable
            v-model="form.startTime"
            type="date"
            value-format="yyyy-MM-dd"
            placeholder="请选择开始充电时间">
          </el-date-picker>
        </el-form-item>
        <el-form-item label="结束充电时间" prop="endTime">
          <el-date-picker clearable
            v-model="form.endTime"
            type="date"
            value-format="yyyy-MM-dd"
            placeholder="请选择结束充电时间">
          </el-date-picker>
        </el-form-item>
        <el-form-item label="用电量(kWh)" prop="powerUsed">
          <el-input v-model="form.powerUsed" placeholder="请输入用电量(kWh)" />
        </el-form-item>
        <el-form-item label="是否异常充电" prop="abnormalFlag">
          <el-input v-model="form.abnormalFlag" placeholder="请输入是否异常充电" />
        </el-form-item>
        <el-form-item label="充电费用" prop="feeAmount">
          <el-input v-model="form.feeAmount" placeholder="请输入充电费用" />
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">确 定</el-button>
        <el-button @click="cancel">取 消</el-button>
      </div>
    </el-dialog>
    <el-dialog
      title="充电统计图"
      :visible.sync="chartDialogVisible"
      width="780px"
      append-to-body
      @close="handleChartDialogClose"
    >
      <div class="chart-dialog">
        <el-form label-width="70px" class="chart-form" :inline="true">
          <el-form-item label="图表">
            <el-radio-group v-model="chartForm.chartType">
              <el-radio-button label="line">折线图</el-radio-button>
              <el-radio-button label="pie">饼图</el-radio-button>
            </el-radio-group>
          </el-form-item>
          <el-form-item label="指标">
            <el-radio-group v-model="chartForm.metric">
              <el-radio-button label="power">用电量</el-radio-button>
              <el-radio-button label="fee">充电费用</el-radio-button>
            </el-radio-group>
          </el-form-item>
          <el-form-item label="粒度">
            <el-select v-model="chartForm.granularity" style="width: 150px">
              <el-option label="按天" value="day" />
              <el-option label="按小时" value="hour" />
            </el-select>
          </el-form-item>
          <el-form-item label="时间">
            <el-date-picker
              v-model="chartForm.dateRange"
              type="daterange"
              range-separator="至"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              value-format="yyyy-MM-dd"
              unlink-panels
              clearable
            />
          </el-form-item>
        </el-form>
        <div class="chart-preview" v-loading="chartLoading">
          <div ref="chartCanvas" class="chart-canvas"></div>
          <div class="chart-empty" v-if="!chartLoading && !chartData.length">
            暂无数据，请选择时间后点击生成
          </div>
        </div>
        <div class="chart-actions">
          <el-button type="primary" icon="el-icon-data-line" @click="generateChart">生成</el-button>
          <el-button
            icon="el-icon-download"
            :disabled="!chartInstance || !chartData.length"
            @click="downloadChart"
          >下载图像</el-button>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { listChargingofCam, getChargingofCam, delChargingofCam, addChargingofCam, updateChargingofCam, statChargingofCam } from "@/api/system/chargingofCam"
import * as echarts from "echarts"

export default {
  name: "ChargingofCam",
  data() {
    return {
      // 遮罩层
      loading: true,
      // 选中数组
      ids: [],
      // 非单个禁用
      single: true,
      // 非多个禁用
      multiple: true,
      // 显示搜索条件
      showSearch: true,
      // 总条数
      total: 0,
      // 电动车充电记录表格数据
      chargingofCamList: [],
      // 弹出层标题
      title: "",
      // 是否显示弹出层
      open: false,
      // 查询参数
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        vehicleId: null,
        stationId: null,
        startTime: null,
        endTime: null,
        powerUsed: null,
        abnormalFlag: null,
        feeAmount: null,
      },
      // 表单参数
      form: {},
      // 表单校验
      rules: {
        vehicleId: [
          { required: true, message: "电动车ID不能为空", trigger: "blur" }
        ],
      },
      // 图表弹窗
      chartDialogVisible: false,
      chartLoading: false,
      chartData: [],
      chartInstance: null,
      chartForm: {
        chartType: "line",
        metric: "power",
        granularity: "day",
        dateRange: []
      }
    }
  },
  created() {
    this.getList()
  },
  mounted() {
    window.addEventListener("resize", this.handleChartResize)
  },
  beforeDestroy() {
    window.removeEventListener("resize", this.handleChartResize)
    this.disposeChart()
  },
  methods: {
    /** 查询电动车充电记录列表 */
    getList() {
      this.loading = true
      listChargingofCam(this.queryParams).then(response => {
        this.chargingofCamList = response.rows
        this.total = response.total
        this.loading = false
      })
    },
    // 取消按钮
    cancel() {
      this.open = false
      this.reset()
    },
    // 表单重置
    reset() {
      this.form = {
        chargeId: null,
        vehicleId: null,
        stationId: null,
        startTime: null,
        endTime: null,
        powerUsed: null,
        abnormalFlag: null,
        feeAmount: null,
        createTime: null
      }
      this.resetForm("form")
    },
    /** 搜索按钮操作 */
    handleQuery() {
      this.queryParams.pageNum = 1
      this.getList()
    },
    /** 重置按钮操作 */
    resetQuery() {
      this.resetForm("queryForm")
      this.handleQuery()
    },
    // 多选框选中数据
    handleSelectionChange(selection) {
      this.ids = selection.map(item => item.chargeId)
      this.single = selection.length!==1
      this.multiple = !selection.length
    },
    /** 新增按钮操作 */
    handleAdd() {
      this.reset()
      this.open = true
      this.title = "添加电动车充电记录"
    },
    /** 修改按钮操作 */
    handleUpdate(row) {
      this.reset()
      const chargeId = row.chargeId || this.ids
      getChargingofCam(chargeId).then(response => {
        this.form = response.data
        this.open = true
        this.title = "修改电动车充电记录"
      })
    },
    /** 提交按钮 */
    submitForm() {
      this.$refs["form"].validate(valid => {
        if (valid) {
          if (this.form.chargeId != null) {
            updateChargingofCam(this.form).then(response => {
              this.$modal.msgSuccess("修改成功")
              this.open = false
              this.getList()
            })
          } else {
            addChargingofCam(this.form).then(response => {
              this.$modal.msgSuccess("新增成功")
              this.open = false
              this.getList()
            })
          }
        }
      })
    },
    /** 删除按钮操作 */
    handleDelete(row) {
      const chargeIds = row.chargeId || this.ids
      this.$modal.confirm('是否确认删除电动车充电记录编号为"' + chargeIds + '"的数据项？').then(function() {
        return delChargingofCam(chargeIds)
      }).then(() => {
        this.getList()
        this.$modal.msgSuccess("删除成功")
      }).catch(() => {})
    },
    /** 导出按钮操作 */
    handleExport() {
      this.download('system/chargingofCam/export', {
        ...this.queryParams
      }, `chargingofCam_${new Date().getTime()}.xlsx`)
    },
    /** 打开统计弹窗 */
    openChartDialog() {
      if (!this.chartForm.dateRange.length) {
        this.chartForm.dateRange = this.getDefaultDateRange()
      }
      this.chartData = []
      this.chartDialogVisible = true
      this.$nextTick(() => {
        const instance = this.ensureChartInstance()
        if (instance) {
          instance.clear()
        }
      })
    },
    /** 请求统计数据并绘制图表 */
    generateChart() {
      if (!this.chartForm.dateRange || this.chartForm.dateRange.length !== 2) {
        this.$message.warning("请选择统计时间范围")
        return
      }
      const [begin, end] = this.chartForm.dateRange
      const params = {
        beginTime: begin ? `${begin} 00:00:00` : undefined,
        endTime: end ? `${end} 23:59:59` : undefined,
        granularity: this.chartForm.granularity
      }
      this.chartLoading = true
      statChargingofCam(params).then(response => {
        const rows = response.data || []
        this.chartData = rows.map(item => ({
          statTime: item.statTime,
          totalPowerUsed: Number(item.totalPowerUsed || 0),
          totalFeeAmount: Number(item.totalFeeAmount || 0)
        }))
        this.$nextTick(() => {
          this.renderChart()
        })
      }).catch(() => {
        this.$message.error("获取统计数据失败")
      }).finally(() => {
        this.chartLoading = false
      })
    },
    /** 将数据渲染到图表 */
    renderChart() {
      const instance = this.ensureChartInstance()
      if (!instance) {
        return
      }
      if (!this.chartData.length) {
        instance.clear()
        return
      }
      const metricKey = this.resolveMetricKey()
      const metricLabel = this.resolveMetricLabel()
      const option = this.chartForm.chartType === "pie"
        ? this.buildPieOption(metricKey, metricLabel)
        : this.buildLineOption(metricKey, metricLabel)
      instance.setOption(option, true)
    },
    /** 构建折线图配置 */
    buildLineOption(metricKey, metricLabel) {
      const xData = this.chartData.map(item => item.statTime)
      const yData = this.chartData.map(item => Number(item[metricKey] || 0))
      return {
        tooltip: { trigger: "axis" },
        grid: { left: "4%", right: "4%", top: 40, bottom: 35, containLabel: true },
        xAxis: { type: "category", boundaryGap: false, data: xData },
        yAxis: { type: "value", name: metricLabel },
        series: [{
          name: metricLabel,
          type: "line",
          data: yData,
          smooth: true,
          areaStyle: {},
          symbol: "circle",
          symbolSize: 8,
          lineStyle: { width: 3 }
        }]
      }
    },
    /** 构建饼图配置 */
    buildPieOption(metricKey, metricLabel) {
      const pieData = this.chartData.map(item => ({
        name: item.statTime,
        value: Number(item[metricKey] || 0)
      }))
      return {
        tooltip: { trigger: "item", formatter: "{b}: {c} ({d}%)" },
        legend: { orient: "vertical", left: "left" },
        series: [{
          name: metricLabel,
          type: "pie",
          radius: ["35%", "65%"],
          center: ["60%", "50%"],
          data: pieData,
          avoidLabelOverlap: false,
          label: { formatter: "{b}: {c}" },
          emphasis: {
            itemStyle: {
              shadowBlur: 10,
              shadowOffsetY: 0,
              shadowColor: "rgba(0, 0, 0, 0.2)"
            }
          }
        }]
      }
    },
    /** 确保实例存在 */
    ensureChartInstance() {
      if (!this.$refs.chartCanvas) {
        return null
      }
      if (!this.chartInstance) {
        this.chartInstance = echarts.init(this.$refs.chartCanvas)
      }
      return this.chartInstance
    },
    resolveMetricKey() {
      return this.chartForm.metric === "power" ? "totalPowerUsed" : "totalFeeAmount"
    },
    resolveMetricLabel() {
      return this.chartForm.metric === "power" ? "用电量(kWh)" : "充电费用(元)"
    },
    /** 下载图像 */
    downloadChart() {
      if (!this.chartInstance || !this.chartData.length) {
        this.$message.warning("请先生成图表")
        return
      }
      const dataUrl = this.chartInstance.getDataURL({
        pixelRatio: 2,
        backgroundColor: "#ffffff"
      })
      const chartLabel = this.chartForm.chartType === "pie" ? "饼图" : "折线图"
      const metricLabel = this.resolveMetricLabel()
      const link = document.createElement("a")
      link.href = dataUrl
      link.download = `充电统计-${metricLabel}-${chartLabel}.png`
      link.click()
    },
    /** 关闭弹窗 */
    handleChartDialogClose() {
      this.chartDialogVisible = false
      this.chartData = []
      this.chartLoading = false
      this.disposeChart()
    },
    disposeChart() {
      if (this.chartInstance) {
        this.chartInstance.dispose()
        this.chartInstance = null
      }
    },
    handleChartResize() {
      if (this.chartInstance) {
        this.chartInstance.resize()
      }
    },
    getDefaultDateRange() {
      const end = new Date()
      const start = new Date()
      start.setDate(end.getDate() - 6)
      return [this.formatDate(start), this.formatDate(end)]
    },
    formatDate(date) {
      const y = date.getFullYear()
      const m = (`0${date.getMonth() + 1}`).slice(-2)
      const d = (`0${date.getDate()}`).slice(-2)
      return `${y}-${m}-${d}`
    }
  }
}
</script>

<style lang="scss" scoped>
.cam-page {
  background: linear-gradient(130deg, #eef2ff 0%, #fbf0ff 45%, #ebf9ff 100%);
  min-height: calc(100vh - 86px);
  padding: 24px;
}

.cam-content {
  max-width: 1200px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.panel {
  --panel-bg: linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(253, 252, 255, 0.92));
  position: relative;
  background:
    var(--panel-bg) padding-box,
    linear-gradient(120deg, rgba(95, 137, 255, 0.35), rgba(241, 148, 255, 0.32), rgba(189, 228, 255, 0.4)) border-box;
  border-radius: 18px;
  border: 4px solid transparent;
  box-shadow: 0 30px 65px -45px rgba(21, 32, 67, 0.9);
  padding: 20px 24px;
  backdrop-filter: blur(8px);
  z-index: 0;
}

.cam-banner {
  --panel-bg: linear-gradient(120deg, rgba(85, 110, 255, 0.18), rgba(234, 86, 255, 0.14));
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.banner-text h2 {
  margin: 0 0 6px;
  font-size: 22px;
  color: #2b2d42;
  font-weight: 600;
}

.banner-text p {
  margin: 0;
  color: #5b6180;
  font-size: 14px;
}

.banner-stat {
  text-align: right;
  color: #252846;
}

.banner-side {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
  min-width: 240px;
}

.chart-cta-btn {
  border: none;
  padding: 12px 28px;
  font-size: 15px;
  border-radius: 999px;
  background: linear-gradient(120deg, #546dff, #8881ff, #ff72c0);
  color: #fff;
  box-shadow: 0 18px 35px -18px rgba(84, 109, 255, 0.9), 0 10px 25px -18px rgba(255, 114, 192, 0.9);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
  animation: chartPulse 2.6s ease-in-out infinite;
}

.chart-cta-btn .el-icon-s-data {
  margin-right: 6px;
}

.chart-cta-btn:hover {
  transform: translateY(-2px) scale(1.02);
  box-shadow: 0 28px 45px -18px rgba(84, 109, 255, 0.85), 0 12px 32px -18px rgba(255, 114, 192, 0.85);
}

.cta-tip {
  font-size: 12px;
  color: #5b6180;
}

@keyframes chartPulse {
  0% {
    box-shadow: 0 0 0 0 rgba(255, 114, 192, 0.3);
  }
  70% {
    box-shadow: 0 0 0 14px rgba(255, 114, 192, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(255, 114, 192, 0);
  }
}

.stat-label {
  font-size: 13px;
  display: block;
  margin-bottom: 4px;
  opacity: 0.8;
}

.stat-value {
  font-size: 34px;
  line-height: 1;
  font-weight: 600;
}

.search-panel {
  padding-bottom: 6px;
}

.cam-form {
  width: 100%;
}

.search-panel ::v-deep .el-form-item {
  margin-right: 12px;
  margin-bottom: 16px;
}

.search-panel ::v-deep .el-input__inner,
.search-panel ::v-deep .el-date-editor .el-input__inner {
  border-radius: 10px;
  background: #f5f7ff;
  border-color: transparent;
  box-shadow: inset 0 0 0 1px rgba(91, 105, 207, 0.08);
}

.search-panel ::v-deep .el-input__inner:focus,
.search-panel ::v-deep .el-date-editor .el-input__inner:focus {
  box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.35);
}

.toolbar-panel {
  padding: 14px 24px 10px;
}

.cam-toolbar {
  width: 100%;
}

.toolbar-panel ::v-deep .el-row {
  align-items: center;
  flex-wrap: wrap;
  row-gap: 8px;
}

.toolbar-panel ::v-deep .el-col {
  min-width: 120px;
}

.toolbar-panel ::v-deep .el-button {
  border-radius: 999px;
  padding: 0 18px;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.toolbar-panel ::v-deep .el-button:hover {
  transform: translateY(-1px);
}

.toolbar-panel ::v-deep .el-button--primary {
  box-shadow: 0 15px 35px -20px rgba(64, 158, 255, 1);
}

.toolbar-panel ::v-deep .right-toolbar {
  margin-left: auto;
  padding-top: 4px;
}

.table-panel {
  padding: 18px 24px 8px;
}

.table-shell {
  border-radius: 18px;
  overflow: hidden;
  border: 4px solid transparent;
  background:
    linear-gradient(180deg, #ffffff, #fdfdff) padding-box,
    linear-gradient(120deg, rgba(93, 144, 255, 0.35), rgba(179, 231, 255, 0.4)) border-box;
  box-shadow: 0 35px 65px -45px rgba(0, 16, 54, 0.9);
}

.table-panel ::v-deep .el-table {
  background-color: white;
}

.table-panel ::v-deep .el-table__header-wrapper th {
  background: linear-gradient(90deg, #f9faff 0%, #f0f4ff 100%);
  color: #475467;
  font-weight: 600;
}

.table-panel ::v-deep .el-table__body tr {
  transition: background 0.2s ease;
}

.table-panel ::v-deep .el-table__body tr:hover > td {
  background: rgba(98, 117, 255, 0.08);
}

.table-panel ::v-deep .el-table .cell {
  color: #2f3142;
}

.pagination-wrap {
  display: flex;
  justify-content: flex-end;
  padding: 16px 4px 0;
}

.chart-dialog {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.chart-form {
  padding: 8px 12px 0;
}

.chart-form ::v-deep .el-form-item {
  margin-right: 16px;
  margin-bottom: 10px;
}

.chart-preview {
  position: relative;
  border: 1px dashed #dcdfe6;
  border-radius: 16px;
  padding: 10px;
  min-height: 340px;
  background: #fff;
}

.chart-canvas {
  width: 100%;
  height: 320px;
}

.chart-empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #909399;
  font-size: 14px;
  pointer-events: none;
}

.chart-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}

@media (max-width: 1180px) {
  .cam-content {
    max-width: 100%;
  }

  .banner-stat {
    text-align: left;
  }
}

@media (max-width: 768px) {
  .cam-page {
    padding: 16px;
  }

  .cam-banner {
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
  }

  .banner-side {
    width: 100%;
    align-items: flex-start;
  }

  .toolbar-panel ::v-deep .el-col {
    min-width: 140px;
  }
}
</style>
